package com.wx.wechat;

import java.nio.charset.StandardCharsets;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.wx.core.process.BaseProcess;
import com.wx.core.process.MsgXmlUtil;
import com.wx.core.process.ProcessManage;
import com.wx.core.process.ProcessResult;
import com.wx.core.process.SignUtil;
import com.wx.core.vo.MsgRequest;
import com.wx.entity.SysWxuser;
import com.wx.util.StringUtils;
import com.wx.util.wxecrypt.AesException;
import com.wx.util.wxecrypt.WXBizMsgCrypt;
import com.wx.vo.EncryptMessage;
import com.zyht.common.AbsPrintBaseController;
import com.zyht.common.xml.XMLUtils;
import com.zyht.wechat.framework.env.WechatEnv;

/**
 * 描述：微信消息入口<br>
 * 作者：ZRB <br>
 * 修改日期：2017年6月21日下午4:28:52 <br>
 */
@Controller
@RequestMapping("anon/wechat")
public class MsgReceiveController extends AbsPrintBaseController {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Resource
	private ProcessManage processManage;

	@RequestMapping(method=RequestMethod.GET, value="callback")
	public void index(String signature, String echostr, String nonce, String timestamp,
			HttpServletRequest req, HttpServletResponse res) throws Exception {
		
		if (!StringUtils.isEmpty(echostr) && !StringUtils.isEmpty(nonce) && !StringUtils.isEmpty(timestamp) && !StringUtils.isEmpty(signature)) {
			String token = WechatEnv.wxuser.getToken();
			boolean flag = SignUtil.validSign(signature, token, timestamp, nonce);
			if (!flag) {
				writeText(res, "");
				return;
			} else {
				writeText(res, echostr);
				return;
			}
		}
		writeText(res, "");
		return;
	}
	
	/**
	 * 方法名称: index<br>
	 * 描述：微信交互入口
	 * 作者: ZRB
	 * 修改日期：2017年6月21日下午4:05:48
	 * @param req
	 * @param res
	 * @throws Exception+
	 *
	 * encrypt_type ->加密类型
	 * msg_signature->消息体签名
	 */
	@RequestMapping(method=RequestMethod.POST, value = "callback")
	public void index(String signature, String timestamp, String nonce, @RequestParam(required=false, value="encrypt_type") String encryptType, @RequestParam(required=false, value="msg_signature") String msgSignature,  
			HttpServletRequest req, HttpServletResponse res) throws Exception {
		MsgRequest msgReq = null;
		String str = IOUtils.toString(req.getInputStream(), StandardCharsets.UTF_8.toString());
		
		boolean isEncrypted = false;
		SysWxuser sysWxuser = WechatEnv.wxuser;
		// 加密传文，安全性校验
		if (!StringUtils.isEmpty(encryptType) && !StringUtils.isEmpty(msgSignature)) {
			isEncrypted = true;
			EncryptMessage message = (EncryptMessage) XMLUtils.getXStream().fromXML(str);
			String xml = decryptXml(message, sysWxuser.getAppid(), sysWxuser.getToken(), sysWxuser.getEncodingaeskey(), signature, timestamp, nonce);
			if(logger.isDebugEnabled()){
				logger.debug("After decode xml is ：\n"+xml);
			}
			msgReq = MsgXmlUtil.parseXmlFromString(xml);
		} else {
			// 非加密传输
			msgReq = MsgXmlUtil.parseXmlFromString(str);
		}

		try {
			String type = msgReq.getMsgType();
			BaseProcess process = processManage.getProcess(type);
			ProcessResult result=(ProcessResult) process.process(req,res, msgReq);
			
			if (isEncrypted) {
				writeText(res, getEncryptResult(result.getResult(), sysWxuser));
			}else{
				String resultContent = result.getResult();
				writeText(res, resultContent==null?"":resultContent);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private String getEncryptResult(String resultXml,SysWxuser sysWxuser){
		String encryptResult ="";
		try {
			String encodingAesKey ="";
			String token = "";
			String appId = "";
			if(sysWxuser!=null){
				encodingAesKey = sysWxuser.getEncodingaeskey();
				token = sysWxuser.getToken();
				appId = sysWxuser.getAppid();
			}
			 
			String timestamp = System.currentTimeMillis()+"";
			String nonce = RandomStringUtils.random(8, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
	
			WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
			encryptResult = pc.encryptMsg(resultXml, timestamp, nonce);
			
		} catch (AesException e) {
			e.printStackTrace();
		}
		return encryptResult;
	}
	
	private String decryptXml(EncryptMessage message,String appid, String token, String encodingKey, String msgSignature,String timestamp,String nonce){
		String ret = "";
		try{
			WXBizMsgCrypt pc = new WXBizMsgCrypt(token,encodingKey,appid);
			String encrypt = message.getEncrypt();
			String format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%1$s]]></Encrypt></xml>";
			String fromXML = String.format(format,encrypt);
			ret = pc.decryptMsg(msgSignature,timestamp + "",nonce,fromXML);
		} catch (AesException e){
			e.printStackTrace();
		}
		return ret;
	}
}
